/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.flink.connector.jdbc.statement;

import org.apache.flink.annotation.PublicEvolving;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;

/**
 * This is a wrapper around {@link PreparedStatement} and allows the users to set parameters by name
 * instead of by index. This allows users to use the same variable parameter multiple times in a
 * statement.
 * 这是 {@link PreparedStatement}的包装，允许用户按名称而不是索引设置参数。 
 * 这允许用户在语句中多次使用相同的变量参数。
 *
 * <p>Code such as this:
 *
 * <pre>
 *   // 按索引设置参数
 *   Connection con = getConnection();
 *   String query = "select * from my_table where first_name=? or last_name=?";
 *   PreparedStatement st = con.prepareStatement(query);
 *   st.setString(1, "bob");
 *   st.setString(2, "bob");
 *   ResultSet rs = st.executeQuery();
 * </pre>
 *
 * <p>Can be replaced with:
 *
 * <pre>
 *   Connection con = getConnection();
 *   // 按名称设置参数
 *   String query = "select * from my_table where first_name=:name or last_name=:name";
 *   
 *   // FieldNamedPreparedStatement.prepareStatement()方法是一个静态方法，
 *   // 用于在给定的数据库连接上创建一个支持以字段名作为参数占位符的预编译语句对象。
 *   // 在这里，使用该方法创建了一个新的 FieldNamedPreparedStatement 对象 st，
 *   // 该对象可以被用于执行具体的 SQL查询或更新操作。
 *   // 传递给FieldNamedPreparedStatement.prepareStatement()方法的
 *   // 字符串数组 {"name"} 表示查询结果集中需要返回的列名。
 *   // 在这里，查询语句 query 返回的结果集中只包含 name 列
 *   FieldNamedPreparedStatement st = FieldNamedPreparedStatement.prepareStatement(con, query, new String[]{"name"});
 *   st.setString(0, "bob");
 *   ResultSet rs = st.executeQuery();
 * </pre>
 */
@PublicEvolving
public interface FieldNamedPreparedStatement extends AutoCloseable {

    /**
     * Creates a <code>NamedPreparedStatement</code> object for sending parameterized SQL statements
     * to the database. 
     * 创建一个 <code>NamedPreparedStatement</code> 对象，用于将参数化SQL语句发送到数据库。
     *
     * @param connection the connection used to connect to database.
     * @param sql 
     *    an SQL statement that may contain one or more ':fieldName' as parameter placeholders
     *    可能包含一个或多个 ':fieldName' 作为参数占位符的 SQL语句
     * 
     * @param fieldNames the field names in schema order used as the parameter names
     *                   用作参数名称的按架构顺序的字段名称
     */
    static FieldNamedPreparedStatement prepareStatement(
            Connection connection, String sql, String[] fieldNames) throws SQLException {
        // 在方法内部，使用 connection.prepareStatement()方法创建一个 PreparedStatement对象，
        // 并将其传递给 FieldNamedPreparedStatement的构造函数，
        // 以创建一个新的 FieldNamedPreparedStatement对象。
        // 如果在创建过程中发生了 SQLException异常，则需要在调用该方法时进行异常处理。
        return FieldNamedPreparedStatementImpl.prepareStatement(connection, sql, fieldNames);
    }

    /**
     * Clears the current parameter values immediately.
     * 立即清除当前参数值。
     *
     * <p>In general, parameter values remain in force for repeated use of a statement. 
     *  一般来说，重复使用语句时参数值仍然有效。
     * 
     * Setting a parameter value automatically clears its previous value. 
     * 设置参数值会自动清除其先前的值。 
     * 
     * However, in some cases it is useful to immediately release the resources 
     * used by the current parameter values; 
     * 然而，在某些情况下，立即释放当前参数值所使用的资源是有用的； 
     * 
     * this can be done by calling the method <code>clearParameters</code>.
     * 这可以通过调用 clearParameters 方法来完成.
     *
     * @see PreparedStatement#clearParameters()
     */
    void clearParameters() throws SQLException;

    /**
     * Executes the SQL query in this <code>NamedPreparedStatement</code> object and returns the
     * <code>ResultSet</code> object generated by the query.
     * 
     * 在此<code>NamedPreparedStatement</code>对象中执行SQL查询，
     * 并返回查询生成的 <code>ResultSet</code> 对象。
     *
     * @see PreparedStatement#executeQuery()
     */
    ResultSet executeQuery() throws SQLException;

    /**
     * Adds a set of parameters to this <code>NamedPreparedStatement</code> object's batch of
     * commands.
     * 向此 <code>NamedPreparedStatement</code>对象的一批命令添加一组参数。
     *
     * @see PreparedStatement#addBatch()
     */
    void addBatch() throws SQLException;

    /**
     * Submits a batch of commands to the database for execution and if all commands execute
     * successfully, returns an array of update counts. 
     * 向数据库提交一批命令以供执行，如果所有命令执行成功，则返回更新计数数组。 
     * 
     * The <code>int</code> elements of the array that is returned are ordered to correspond 
     * to the commands in the batch, which are ordered according to the order 
     * in which they were added to the batch.
     * 
     * 返回的数组的 <code>int</code>元素经过排序，与批处理中的命令相对应，
     * 这些命令根据添加到批处理中的顺序进行排序。
     *
     * @see PreparedStatement#executeBatch()
     */
    int[] executeBatch() throws SQLException;

    /**
     * Sets the designated parameter to SQL <code>NULL</code>.
     * 将指定参数设置为 SQL <code>NULL</code>。
     *
     * <p><B>Note:</B> You must specify the parameter's SQL type.
     *    <B>注意：</B>您必须指定参数的SQL类型。
     *
     * @see PreparedStatement#setNull(int, int)
     */
    void setNull(int fieldIndex, int sqlType) throws SQLException;

    /**
     * Sets the designated parameter to the given Java <code>boolean</code> value. The driver
     * converts this to an SQL <code>BIT</code> or <code>BOOLEAN</code> value when it sends it to
     * the database.
     *
     * @see PreparedStatement#setBoolean(int, boolean)
     */
    void setBoolean(int fieldIndex, boolean x) throws SQLException;

    /**
     * Sets the designated parameter to the given Java <code>byte</code> value. The driver converts
     * this to an SQL <code>TINYINT</code> value when it sends it to the database.
     *
     * @see PreparedStatement#setByte(int, byte)
     */
    void setByte(int fieldIndex, byte x) throws SQLException;

    /**
     * Sets the designated parameter to the given Java <code>short</code> value. The driver converts
     * this to an SQL <code>SMALLINT</code> value when it sends it to the database.
     *
     * @see PreparedStatement#setShort(int, short)
     */
    void setShort(int fieldIndex, short x) throws SQLException;

    /**
     * Sets the designated parameter to the given Java <code>int</code> value. The driver converts
     * this to an SQL <code>INTEGER</code> value when it sends it to the database.
     *
     * @see PreparedStatement#setInt(int, int)
     */
    void setInt(int fieldIndex, int x) throws SQLException;

    /**
     * Sets the designated parameter to the given Java <code>long</code> value. The driver converts
     * this to an SQL <code>BIGINT</code> value when it sends it to the database.
     *
     * @see PreparedStatement#setLong(int, long)
     */
    void setLong(int fieldIndex, long x) throws SQLException;

    /**
     * Sets the designated parameter to the given Java <code>float</code> value. The driver converts
     * this to an SQL <code>REAL</code> value when it sends it to the database.
     *
     * @see PreparedStatement#setFloat(int, float)
     */
    void setFloat(int fieldIndex, float x) throws SQLException;

    /**
     * Sets the designated parameter to the given Java <code>double</code> value. The driver
     * converts this to an SQL <code>DOUBLE</code> value when it sends it to the database.
     *
     * @see PreparedStatement#setDouble(int, double)
     */
    void setDouble(int fieldIndex, double x) throws SQLException;

    /**
     * Sets the designated parameter to the given <code>java.math.BigDecimal</code> value. The
     * driver converts this to an SQL <code>NUMERIC</code> value when it sends it to the database.
     *
     * @see PreparedStatement#setBigDecimal(int, BigDecimal)
     */
    void setBigDecimal(int fieldIndex, BigDecimal x) throws SQLException;

    /**
     * Sets the designated parameter to the given Java <code>String</code> value. The driver
     * converts this to an SQL <code>VARCHAR</code> or <code>LONGVARCHAR</code> value (depending on
     * the argument's size relative to the driver's limits on <code>VARCHAR</code> values) when it
     * sends it to the database.
     *
     * @see PreparedStatement#setString(int, String)
     */
    void setString(int fieldIndex, String x) throws SQLException;

    /**
     * Sets the designated parameter to the given Java array of bytes. The driver converts this to
     * an SQL <code>VARBINARY</code> or <code>LONGVARBINARY</code> (depending on the argument's size
     * relative to the driver's limits on <code>VARBINARY</code> values) when it sends it to the
     * database.
     *
     * @see PreparedStatement#setBytes(int, byte[])
     */
    void setBytes(int fieldIndex, byte[] x) throws SQLException;

    /**
     * Sets the designated parameter to the given <code>java.sql.Date</code> value using the default
     * time zone of the virtual machine that is running the application. The driver converts this to
     * an SQL <code>DATE</code> value when it sends it to the database.
     *
     * @see PreparedStatement#setDate(int, Date)
     */
    void setDate(int fieldIndex, java.sql.Date x) throws SQLException;

    /**
     * Sets the designated parameter to the given <code>java.sql.Time</code> value. The driver
     * converts this to an SQL <code>TIME</code> value when it sends it to the database.
     *
     * @see PreparedStatement#setTime(int, Time)
     */
    void setTime(int fieldIndex, java.sql.Time x) throws SQLException;

    /**
     * Sets the designated parameter to the given <code>java.sql.Timestamp</code> value. The driver
     * converts this to an SQL <code>TIMESTAMP</code> value when it sends it to the database.
     *
     * @see PreparedStatement#setTimestamp(int, Timestamp)
     */
    void setTimestamp(int fieldIndex, java.sql.Timestamp x) throws SQLException;

    /**
     * Sets the value of the designated parameter using the given object.
     *
     * @see PreparedStatement#setObject(int, Object)
     */
    void setObject(int fieldIndex, Object x) throws SQLException;

    /**
     * Releases this <code>Statement</code> object's database and JDBC resources immediately instead
     * of waiting for this to happen when it is automatically closed. It is generally good practice
     * to release resources as soon as you are finished with them to avoid tying up database
     * resources.
     *
     * @see PreparedStatement#close()
     */
    void close() throws SQLException;
}
